// Watch的作用是处理渲染逻辑,简单来说是实现页面的局部更新
/**
 * Watch 是 观察者
 * 每个属性有一个dep(属性就是被观察者),watcher就是观察者(属性更新通知观察者来更新) ---> 这个就是观察者模式
 */
import Dep, { popTarget, pushTarget } from "./dep";

//  就是封装 vm._update(vm._render()); --> 这个是模板引擎实现的主要方法
let id = 0;
class Watch {
  constructor(vm, exprOrFn, options, cb) {
    this.id = id++;
    this.renderWarcher = options; //是一个渲染过程
    if(typeof exprOrFn === "string") {
      this.getter = function() {
        return vm[exprOrFn];
      }
    }else {
      this.getter = exprOrFn;
    }
    // this.getter = fn;
    this.deps = [];
    this.cb = cb;
    this.depsId = new Set(); //为了去重
    this.lazy = options.lazy;
    this.dirty = this.lazy;
    this.vm = vm;
    this.user = options.user; //标识是否是用户的watcher

    this.value = this.lazy ? undefined : this.get();//默认第一次调用渲染页面
  }
  addDep(dep) {
    let id = dep.id;
    if (!this.depsId.has(id)) {
      this.deps.push(dep);
      this.depsId.add(id);
      dep.addSub(this);
    }
  }
  //组件缓存
  evaluate() {
    this.value = this.get();
    this.dirty = false;
  }
  get() {
    pushTarget(this);
    let value = this.getter.call(this.vm);
    popTarget();
    return value;
  }
  depend() {
    let i = this.deps.length
    while(i--) {
      this.deps[i].depend();
    }
  }
  update() {
    if(this.lazy) {
      this.dirty = true;
    }else {
      queueWatcher(this); //实现异步更新
    }
  }
  run() {
    let oldValue = this.value;
    let newValue = this.get();
    if(this.user) {
      this.cb.call(this.vm,newValue, oldValue);
    }
  }
}
let queue = [];
let has = {};
let pending = false; //防抖
function flushSchedulerQueue() {
  let flushSchQueue = queue.slice(0);
  queue = [];
  has = {};
  pending = false;
  flushSchQueue.forEach(q => q.run());
}
function queueWatcher(watcher) { //实现异步刷新入口函数
  const id = watcher.id;
  if (!has[id]) {
    queue.push(watcher);
    has[id] = true;
    if (!pending) {
      nextTick(flushSchedulerQueue, 0)
      pending = true;
    }
  }
}
let callbacks = [];
let waiting = false;
function flushCallbacks() {
  let cbs = callbacks.slice(0);
  waiting = false;
  callbacks = [];
  cbs.forEach(cb => cb());
}
// 这里是为了提升异步更新的性能
let timeFunc;
if (Promise) {
  timeFunc = () => {
    Promise.resolve().then(flushCallbacks);
  }
} else if (MutationObserver) {
  let observer = new MutationObserver(flushCallbacks);
  let textNode = document.createTextNode(1);
  observer.observe(textNode, {
    characterData: true
  });
  timeFunc = () => {
    textNode.textContent = 2;
  }
} else if (setImmediate) {
  timeFunc = () => {
    setImmediate(flushCallbacks);
  }
} else {
  timeFunc = () => {
    setTimeout(flushCallbacks);
  }
}
export function nextTick(cb) {
  callbacks.push(cb);
  if (!waiting) {
    timeFunc();
  }
}

export default Watch;
// dep 就是视图中的属性(数据{{name}})
// dep和watCH 的关系是多对多的


